home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xpaint-2.1.1
/
brushOp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
13KB
|
466 lines
/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, 1993, David Koblas (koblas@netcom.com) | */
/* | | */
/* | Permission to use, copy, modify, and to distribute this software | */
/* | and its documentation for any purpose is hereby granted without | */
/* | fee, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. There is no | */
/* | representations about the suitability of this software for | */
/* | any purpose. this software is provided "as is" without express | */
/* | or implied warranty. | */
/* | | */
/* +-------------------------------------------------------------------+ */
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Toggle.h>
#include "xpaint.h"
#include "misc.h"
#include "Paint.h"
#include "bitmaps/paintA.xbm"
#include "bitmaps/paintB.xbm"
#include "bitmaps/paintC.xbm"
#include "bitmaps/paintD.xbm"
#include "bitmaps/paintE.xbm"
#include "bitmaps/paintF.xbm"
#include "bitmaps/paintG.xbm"
#include "bitmaps/paintH.xbm"
#include "bitmaps/paintI.xbm"
#include "bitmaps/paintJ.xbm"
#include "bitmaps/paintK.xbm"
#include "bitmaps/paintL.xbm"
#include "bitmaps/paintM.xbm"
#include "bitmaps/paintN.xbm"
#include "bitmaps/paintO.xbm"
#include "bitmaps/paintP.xbm"
#include "bitmaps/paintQ.xbm"
#include "bitmaps/paintR.xbm"
#include "bitmaps/paintS.xbm"
#include "bitmaps/paintT.xbm"
#define BRUSH(name) \
(char *)CONCAT(name,_bits), CONCAT(name,_width), CONCAT(name,_height)
typedef struct {
Pixmap pixmap;
Cursor cursor;
char *bits;
int width, height;
} BrushItem;
static BrushItem brushList[] = {
{ None, None, BRUSH(paintA) },
{ None, None, BRUSH(paintB) },
{ None, None, BRUSH(paintC) },
{ None, None, BRUSH(paintD) },
{ None, None, BRUSH(paintE) },
{ None, None, BRUSH(paintF) },
{ None, None, BRUSH(paintG) },
{ None, None, BRUSH(paintH) },
{ None, None, BRUSH(paintI) },
{ None, None, BRUSH(paintJ) },
{ None, None, BRUSH(paintK) },
{ None, None, BRUSH(paintL) },
{ None, None, BRUSH(paintM) },
{ None, None, BRUSH(paintN) },
{ None, None, BRUSH(paintO) },
{ None, None, BRUSH(paintP) },
{ None, None, BRUSH(paintQ) },
{ None, None, BRUSH(paintR) },
{ None, None, BRUSH(paintS) },
{ None, None, BRUSH(paintT) },
};
#define default_bits paintA_bits
#define default_width paintA_width
#define default_height paintA_height
typedef struct {
Boolean isErase, useSecond;
Pixmap pixmap;
int width, height;
} LocalInfo;
static BrushItem *currentBrush = NULL;
static Boolean eraseMode = True;
static void draw(Widget w, OpInfo *info, LocalInfo *l, int x, int y)
{
XRectangle undo;
int sx = x - l->width / 2;
int sy = y - l->height / 2;
GC gc;
if (l->isErase)
gc = info->base_gc;
else
gc = l->useSecond ? info->second_gc : info->first_gc;
XSetClipOrigin(XtDisplay(w), gc, sx, sy);
if (l->isErase && eraseMode && info->base != None) {
XCopyArea(XtDisplay(w), info->base, info->drawable,
gc, sx, sy, l->width, l->height, sx, sy);
} else {
XFillRectangle(XtDisplay(w), info->drawable,
gc, sx, sy, l->width, l->height);
}
if (info->surface == opPixmap) {
XYtoRECT(sx, sy, sx + l->width, sy + l->height, &undo);
UndoGrow(w, sx, sy);
UndoGrow(w, sx + l->width, sy + l->height);
PwUpdate(w, &undo, False);
}
}
static void press(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
{
/*
** Check to make sure all buttons are up, before doing this
*/
if ((event->state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)) != 0)
return;
if (info->surface == opWindow && info->isFat)
return;
l->useSecond = event->button == Button2;
l->width = currentBrush->width;
l->height = currentBrush->height;
XSetClipMask(XtDisplay(w), info->first_gc, l->pixmap);
XSetClipMask(XtDisplay(w), info->second_gc, l->pixmap);
XSetClipMask(XtDisplay(w), info->base_gc, l->pixmap);
UndoStart(w, info);
draw(w, info, l, event->x, event->y);
}
static void motion(Widget w, LocalInfo *l, XMotionEvent *event, OpInfo *info)
{
if (info->surface == opWindow && info->isFat)
return;
draw(w, info, l, event->x, event->y);
}
static void release(Widget w, LocalInfo *l, XButtonEvent *event, OpInfo *info)
{
int mask;
/*
** Check to make sure all buttons are up, before doing this
*/
mask = Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask;
switch (event->button) {
case Button1: mask ^= Button1Mask; break;
case Button2: mask ^= Button2Mask; break;
case Button3: mask ^= Button3Mask; break;
case Button4: mask ^= Button4Mask; break;
case Button5: mask ^= Button5Mask; break;
}
if ((event->state & mask) != 0)
return;
XSetClipMask(XtDisplay(w), info->first_gc, None);
XSetClipMask(XtDisplay(w), info->second_gc, None);
XSetClipMask(XtDisplay(w), info->base_gc, None);
}
static void setPixmap(Widget w, void *brushArg)
{
BrushItem *brush = (BrushItem *)brushArg;
LocalInfo *l = (LocalInfo*)GraphicGetData(w);
l->pixmap = brush->pixmap;
}
static void setCursor(Widget w, void *brushArg)
{
static Boolean inited = False;
static XColor xcols[2];
BrushItem *brush = (BrushItem *)brushArg;
Display *dpy = XtDisplay(w);
if (!inited) {
Colormap map;
Screen *screen = XtScreen(w);
inited = True;
xcols[0].pixel = WhitePixelOfScreen(screen);
xcols[1].pixel = BlackPixelOfScreen(screen);
XtVaGetValues(w, XtNcolormap, &map, NULL);
XQueryColors(dpy, map, xcols, XtNumber(xcols));
}
if (brush->cursor == None) {
Pixmap mask;
XImage *src, *msk;
GC gc;
Boolean flg;
int x, y;
src = XGetImage(dpy, brush->pixmap, 0, 0, brush->width,
brush->height, AllPlanes, ZPixmap);
msk = NewXImage(dpy, NULL, 1, brush->width, brush->height);
for (y = 0; y < brush->height; y++) {
for (x = 0; x < brush->width; x++) {
Pixel p = XGetPixel(src, x, y);
flg = (Boolean)p;
if (!flg && x > 0)
flg = XGetPixel(src, x - 1, y);
if (!flg && x < brush->width - 1)
flg = XGetPixel(src, x + 1, y);
if (!flg && y > 0)
flg = XGetPixel(src, x, y - 1);
if (!flg && y < brush->height - 1)
flg = XGetPixel(src, x, y + 1);
XPutPixel(msk, x, y, flg);
}
}
mask = XCreatePixmap(dpy, brush->pixmap, brush->width, brush->height, 1);
gc = XCreateGC(dpy, mask, 0, 0);
XPutImage(dpy, mask, gc, msk, 0, 0, 0, 0, brush->width, brush->height);
XDestroyImage(src);
XDestroyImage(msk);
XFreeGC(dpy, gc);
brush->cursor = XCreatePixmapCursor(dpy, brush->pixmap, mask,
&xcols[1], &xcols[0],
brush->width / 2, brush->height / 2);
XFreePixmap(dpy, mask);
}
XtVaSetValues(w, XtNcursor, brush->cursor, NULL);
}
/*
** Those public functions
*/
Boolean EraseGetMode()
{
return eraseMode;
}
void EraseSetMode(Boolean mode)
{
eraseMode = mode;
}
void *BrushAdd(Widget w)
{
LocalInfo *l = XtNew(LocalInfo);
XtVaSetValues(w, XtNcompress, False, NULL);
l->isErase = False;
l->pixmap = currentBrush->pixmap;
OpAddEventHandler(w, opWindow|opPixmap, ButtonPressMask,
FALSE, (OpEventProc)press, (XtPointer)l);
OpAddEventHandler(w, opWindow|opPixmap, ButtonMotionMask,
FALSE, (OpEventProc)motion, (XtPointer)l);
OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask,
FALSE, (OpEventProc)release, (XtPointer)l);
setCursor(w, (void*)currentBrush);
return l;
}
void BrushRemove(Widget w, LocalInfo *l)
{
OpRemoveEventHandler(w, opWindow|opPixmap, ButtonPressMask,
FALSE, (OpEventProc)press, (XtPointer)l);
OpRemoveEventHandler(w, opWindow|opPixmap, ButtonMotionMask,
FALSE, (OpEventProc)motion, (XtPointer)l);
OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask,
FALSE, (OpEventProc)release, (XtPointer)l);
XtFree((XtPointer)l);
}
void *EraseAdd(Widget w)
{
LocalInfo *l = XtNew(LocalInfo);
XtVaSetValues(w, XtNcompress, False, NULL);
l->isErase = True;
l->pixmap = currentBrush->pixmap;
OpAddEventHandler(w, opWindow|opPixmap, ButtonPressMask,
FALSE, (OpEventProc)press, (XtPointer)l);
OpAddEventHandler(w, opWindow|opPixmap, ButtonMotionMask,
FALSE, (OpEventProc)motion, (XtPointer)l);
OpAddEventHandler(w, opWindow|opPixmap, ButtonReleaseMask,
FALSE, (OpEventProc)release, (XtPointer)l);
setCursor(w, (void*)currentBrush);
return l;
}
void EraseRemove(Widget w, LocalInfo *l)
{
OpRemoveEventHandler(w, opWindow|opPixmap, ButtonPressMask,
FALSE, (OpEventProc)press, (XtPointer)l);
OpRemoveEventHandler(w, opWindow|opPixmap, ButtonMotionMask,
FALSE, (OpEventProc)motion, (XtPointer)l);
OpRemoveEventHandler(w, opWindow|opPixmap, ButtonReleaseMask,
FALSE, (OpEventProc)release, (XtPointer)l);
XtFree((XtPointer)l);
}
/*
** Initializer to create a default brush
*/
void BrushInit(Widget toplevel)
{
currentBrush = &brushList[0];
currentBrush->pixmap = XCreatePixmapFromBitmapData(
XtDisplay(toplevel),
RootWindowOfScreen(XtScreen(toplevel)),
currentBrush->bits,
currentBrush->width,
currentBrush->height,
False, True, 1);
}
/*
** The brush selection dialog
*/
static void closePopup(Widget button, Widget shell)
{
XtPopdown(shell);
}
static void selectBrush(Widget shell, BrushItem *nc)
{
currentBrush = nc;
if (((int)CurrentOp[0] == (int)BrushAdd) ||
((int)CurrentOp[0] == (int)EraseAdd)) {
GraphicAll(setCursor, (void*)currentBrush);
GraphicAll(setPixmap, (void*)currentBrush);
}
}
static Widget createDialog(Widget w)
{
Widget shell, form, box, icon, firstIcon = 0, close;
GC gc, igc;
XGCValues values;
int i;
Pixel fg, bg;
Pixmap pix;
shell = XtVaCreatePopupShell("brush",
topLevelShellWidgetClass, w,
NULL);
form = XtVaCreateManagedWidget(NULL,
formWidgetClass, shell,
NULL);
box = XtVaCreateManagedWidget("box",
boxWidgetClass, form,
NULL);
values.foreground = WhitePixelOfScreen(XtScreen(w));
values.background = BlackPixelOfScreen(XtScreen(w));
gc = XCreateGC(XtDisplay(w),
RootWindowOfScreen(XtScreen(w)),
GCForeground|GCBackground, &values);
values.background = WhitePixelOfScreen(XtScreen(w));
values.foreground = BlackPixelOfScreen(XtScreen(w));
igc = XCreateGC(XtDisplay(w),
RootWindowOfScreen(XtScreen(w)),
GCForeground|GCBackground, &values);
for (i = 0; i < XtNumber(brushList); i++) {
if (brushList[i].pixmap == None)
brushList[i].pixmap = XCreatePixmapFromBitmapData(
XtDisplay(box),
RootWindowOfScreen(XtScreen(box)),
brushList[i].bits,
brushList[i].width,
brushList[i].height,
False, True, 1);
icon = XtVaCreateManagedWidget("icon",
toggleWidgetClass, box,
XtNradioGroup, firstIcon,
NULL);
pix = XCreatePixmap(XtDisplay(box),
RootWindowOfScreen(XtScreen(box)),
brushList[i].width,
brushList[i].height,
DefaultDepthOfScreen(XtScreen(box)));
XtVaGetValues(icon, XtNforeground, &fg,
XtNbackground, &bg,
NULL);
/*
** Clear then draw the clipped rectangle in
*/
XSetClipMask(XtDisplay(w), gc, None);
XSetForeground(XtDisplay(w), gc, bg);
XFillRectangle(XtDisplay(w), pix, gc, 0, 0,
brushList[i].width, brushList[i].height);
XSetClipMask(XtDisplay(w), gc, brushList[i].pixmap);
XSetForeground(XtDisplay(w), gc, fg);
XFillRectangle(XtDisplay(w), pix, gc, 0, 0,
brushList[i].width, brushList[i].height);
XtVaSetValues(icon, XtNbitmap, pix, NULL);
if (firstIcon == NULL) {
XtVaSetValues(icon, XtNstate, True, NULL);
firstIcon = icon;
}
XtAddCallback(icon, XtNcallback,
(XtCallbackProc)selectBrush, (XtPointer)&brushList[i]);
}
close = XtVaCreateManagedWidget("close",
commandWidgetClass, form,
XtNfromVert, box,
XtNtop, XtChainBottom,
NULL);
XtAddCallback(close, XtNcallback, (XtCallbackProc)closePopup, (XtPointer)shell);
XFreeGC(XtDisplay(w), gc);
XFreeGC(XtDisplay(w), igc);
AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))closePopup, shell);
return shell;
}
void BrushSelect(Widget w)
{
static Widget popup = NULL;
if (popup == NULL)
popup = createDialog(GetToplevel(w));
XtPopup(popup, XtGrabNone);
XMapRaised(XtDisplay(popup), XtWindow(popup));
}